'''
copyright: Copyright (C) 2015-2024, Wazuh Inc.

           Created by Wazuh, Inc. <info@wazuh.com>.

           This program is free software; you can redistribute it and/or modify it under the terms of GPLv2

type: integration

brief: Wazuh is able to detect vulnerabilities in the applications installed in agents using the Vulnerability Detector
       module. This software audit is performed through the integration of vulnerability feeds indexed by Redhat,
       Canonical, Debian, Amazon Linux and NVD Database.

components:
    - vulnerability_detector

suite: scan_results

targets:
    - manager

daemons:
    - wazuh-modulesd
    - wazuh-db
    - wazuh-analysisd

os_platform:
    - linux

os_version:
    - Arch Linux
    - Amazon Linux 2
    - Amazon Linux 1
    - CentOS 8
    - CentOS 7
    - Debian Buster
    - Red Hat 8
    - Ubuntu Focal
    - Ubuntu Bionic
    - SUSE Enterprise Desktop 11
    - SUSE Enterprise Desktop 12
    - SUSE Enterprise Desktop 15
    - SUSE Enterprise Server 11
    - SUSE Enterprise Server 12
    - SUSE Enterprise Server 15

references:
    - https://documentation.wazuh.com/current/user-manual/capabilities/vulnerability-detection/index.html

tags:
    - vulnerability
    - vulnerability_detector
    - scan_results
'''
import pytest
from pathlib import Path

from wazuh_testing.constants.daemons import ANALYSISD_DAEMON, MODULES_DAEMON, SYSCHECK_DAEMON
from wazuh_testing.constants.paths.databases import CPE_HELPER_PATH
from wazuh_testing.constants.paths.logs import WAZUH_LOG_PATH, ALERTS_JSON_PATH
from wazuh_testing.utils.callbacks import generate_callback
from wazuh_testing.utils.db_queries import agent_db
from wazuh_testing.utils.file import read_json_file, copy, write_json_file
from wazuh_testing.tools.monitors.file_monitor import FileMonitor
from wazuh_testing.utils.configuration import (get_test_cases_data, load_configuration_template,
                                               update_configuration_template)
from wazuh_testing.modules.modulesd.vulnerability_detector import patterns as cb
from wazuh_testing.modules.modulesd.configuration import MODULESD_DEBUG
from wazuh_testing.modules.monitord.configuration import MONITORD_ROTATE_LOG
from wazuh_testing.utils.mocking import VULNERABLE_PACKAGES
from test_vulnerability_detector import utils as ev
from . import TEST_CASES_PATH, CONFIGURATIONS_PATH, custom_nvd_json_feed_path, custom_cpe_helper_path


pytest.skip("The tests will be deprecated, they test the old Vulnerability Detector.", allow_module_level=True)

# Variables
local_internal_options = {MODULESD_DEBUG: '2', MONITORD_ROTATE_LOG: '0'}
daemons_handler_configuration = {'daemons': [ANALYSISD_DAEMON, MODULES_DAEMON, SYSCHECK_DAEMON]}
pytestmark = [pytest.mark.server]

# Configuration and cases data
configurations_path = Path(CONFIGURATIONS_PATH, 'configuration_scan_nvd_vulnerabilities.yaml')
t1_cases_path = Path(TEST_CASES_PATH, 'cases_scan_nvd_vulnerabilities.yaml')
t2_cases_path = Path(TEST_CASES_PATH, 'cases_no_agent_data.yaml')


# Scan NVD test configurations (t1)
t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path)
t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters,
                                                t1_configuration_metadata)
t1_systems = [metadata['system'] for metadata in t1_configuration_metadata]

# No agent data test configurations (t2)
t2_configuration_parameters, t2_configuration_metadata, t2_case_ids = get_test_cases_data(t2_cases_path)
t2_configurations = load_configuration_template(configurations_path, t2_configuration_parameters,
                                                t2_configuration_metadata)
t2_systems = [metadata['system'] for metadata in t2_configuration_metadata]

# Set offline custom feeds configuration
t1_configurations = update_configuration_template(t1_configurations, ['CUSTOM_NVD_JSON_PATH'],
                                                  [custom_nvd_json_feed_path])
t2_configurations = update_configuration_template(t2_configurations, ['CUSTOM_NVD_JSON_PATH'],
                                                  [custom_nvd_json_feed_path])


@pytest.mark.tier(level=1)
@pytest.mark.parametrize('test_configuration, test_metadata, agent_system',
                         zip(t1_configurations, t1_configuration_metadata, t1_systems), ids=t1_case_ids)
def test_scan_nvd_vulnerabilities(test_configuration, test_metadata, agent_system, set_wazuh_configuration,
                                  configure_local_internal_options, truncate_monitored_files, clean_cve_tables,
                                  prepare_scan, daemons_handler):
    '''
    description: Check if the corresponding vulnerability alerts and logs are generated after scanning with an NVD feed
                 and custom vulnerable packages, using only the NVD feed.This is tested for macOS and Windows system.

    test_phases:
        - setup:
            - Set a custom Wazuh configuration.
            - Mock an agent.
            - If Windows, then set a custom CPE helper.
            - Clean CVE table.
            - Force a full scan.
            - Restart wazuh-modulesd.
        - test:
            - Check that the vulnerabilities of each package have been detected.
            - Check that vulnerability alerts have been generated for all packages.
        - teardown:
            - Restart initial wazuh configuration.
            - Clean CVE table.

    wazuh_min_version: 4.4.0

    tier: 1

    parameters:
        - test_configuration:
            type: dict
            brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture.
        - test_metadata:
            type: dict
            brief: Wazuh configuration metadata
        - agent_system:
             type: str
             brief: System to set to the mocked agent.
        - set_wazuh_configuration:
            type: fixture
            brief: Set the wazuh configuration according to the configuration data.
        - configure_local_internal_options:
            type: fixture
            brief: Set local_internal_options configuration.
        - truncate_monitored_files:
            type: fixture
            brief: Truncate all the log files and json alerts files before and after the test execution.
        - clean_cve_tables:
            type: fixture
            brief: Clean all CVE tables.
        - prepare_scan:
            type: fixture
            brief: Setup the initial test state.
        - daemons_handler:
            type: fixture
            brief: Restart the wazuh-modulesd daemon.

    assertions:
        - Verify that the log vulnerability report appears in ossec.log for each vulnerable package.
        - Verify that the alert vulnerability report appears in alerts.json for each vulnerable package.

    input_description:
        - The `scan_nvd_vulnerabilities.yaml` file provides the module configuration for this test.
        - The `cases_scan_nvd_vulnerabilities.yaml` file provides the test cases.

    expected_output:
        - f"The '{package}' package .* from agent '{agent_id}' is vulnerable to '{cve}'"
        - f".*"agent":."id":"{agent_id}".*{cve} affects {package}"
    '''
    agent_id = prepare_scan
    for package in VULNERABLE_PACKAGES:

        log_present = ev.check_cve_affects_package_log(agent_id, package['name'], package['cveid'])
        assert log_present is not None, f"Expected 'package {package['name']} is vulnerable to cve' log not found"

        log_present = ev.check_cve_affects_package_alert(agent_id, package['name'], package['cveid'])
        assert log_present is not None, f"Expected '{package['cveid']} affects {package['name']}' alert not found"


@pytest.mark.tier(level=0)
@pytest.mark.parametrize('test_configuration, test_metadata, agent_system',
                         zip(t2_configurations, t2_configuration_metadata, t2_systems), ids=t2_case_ids)
def test_no_agent_data(test_configuration, test_metadata, agent_system, set_wazuh_configuration,
                       configure_local_internal_options, truncate_monitored_files, clean_cve_tables,
                       prepare_scan, daemons_handler):
    '''
    description: Check that a Warning message is displayed when attempting to perform a vulnerability scan using only
                 the NVD feed for Linux systems.

    test_phases:
        - setup:
            - Set a custom Wazuh configuration.
            - Mock an agent.
            - If Windows, then set a custom CPE helper.
            - Clean CVE table.
            - Force a full scan.
            - Restart wazuh-modulesd.
        - test:
            - Check that the warning message of 'unavailable vulnerability agent' data appears.
        - teardown:
            - Restart initial wazuh configuration.
            - Clean CVE table.

    wazuh_min_version: 4.4.0

    tier: 0

    parameters:
        - test_configuration:
            type: dict
            brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture.
        - test_metadata:
            type: dict
            brief: Wazuh configuration metadata
        - agent_system:
             type: str
             brief: System to set to the mocked agent.
        - set_wazuh_configuration:
            type: fixture
            brief: Set the wazuh configuration according to the configuration data.
        - configure_local_internal_options:
            type: fixture
            brief: Set local_internal_options configuration.
        - truncate_monitored_files:
            type: fixture
            brief: Truncate all the log files and json alerts files before and after the test execution.
        - clean_cve_tables:
            type: fixture
            brief: Clean all CVE tables.
        - prepare_scan:
            type: fixture
            brief: Setup the initial test state.
        - daemons_handler:
            type: fixture
            brief: Restart the wazuh-modulesd daemon.

    assertions:
        - Verify that the warning message is displayed when using only the NVD feed in Linux systen scans.

    input_description:
        - The `scan_nvd_vulnerabilities.yaml` file provides the module configuration for this test.
        - The `cases_no_agent_data.yaml` file provides the test cases.

    expected_output:
        - f"Unavailable vulnerability data for the agent '{agent_id}' OS. Skipping it"
    '''
    log_monitor = FileMonitor(WAZUH_LOG_PATH)

    callback = generate_callback(regex=cb.VULN_DATA_UNAVAILABLE, replacement={"agent_id": prepare_scan})
    log_monitor.start(callback=callback, timeout=20)
    assert log_monitor.callback_result is not None, f"Expected 'Unavailable vulnerability data...' event not found."
